
#include "point_container.hpp"

struct MyPoint : public Point_Base_st {
    POINT_METHOD_CLONE_IMPLEMENT (MyPoint)  // 当需要实现自定义的派生类型时, 需要将 clone 函数进行 override

    MyPoint (std::uint16_t _no, std::uint8_t _info = 0) :
        Point_Base_st {_no}, _info {_info} {}  // 委托构造


    /// 另外 clone 函数一定程度依赖于对应的复制构造函数, 如果派生类的实现中使用了动态内存等其他资源并需要进行深拷贝时, 则需要手动实现复制构造函数的细节
    /// 反之如果派生类没有使用这些特殊资源, 则不需要将复制构造函数进行手动实现
    /// 比如本类 MyPoint 成员变量全是基本型, 则不需要显式地写出复制构造函数:
    ///         MyPoint (const MyPoint & _other) {  // 手动实现深拷贝
    ///         }

    std::uint8_t _info;
};

MyPoint mp[10] = {
        {1},
        {2},
        {3},
        {4},
        {5},
        {6},
        {7},
        {8},
        {9},
        {10},
};

// 测试单线的增删改查等功能
void test_Linear () {

    // 打印航线, 格式 "点编号(点额外信息)"
    // 因为在插入, 删除等操作时会自动更新航点编号, 所以使用航点类型来标识这是更新后的航点
    #define PRINT(str)                                             \
        do {                                                       \
            std::printf ("%s: ", str);                             \
            for (auto i = 0; i < l.counts (); i++) {               \
                MyPoint * p = dynamic_cast<MyPoint *> (l.get (i)); \
                if (p) std::printf ("%d(%d) ", p->_no, p->_info);  \
            }                                                      \
            std::printf ("\n");                                    \
        } while (0)

    Linear_Container_ct l;

    // 初始化, 线编号 100
    l.init (100);

    // 线 ID 读写测试
    std::printf ("line id = %u\n", l.id ());
    l.id () = 101;
    std::printf ("line id = %u\n", l.id ());

    for (auto & p : mp)
        l.append (p);

    // 打印元素个数
    std::printf ("counts = %d\n", l.counts ());


    // 根据航点编号取出航点
    Point_Base_st *p1 = nullptr,
                  *p2 = nullptr,
                  *p3 = nullptr;


    l.get (3, &p1);  // 用实参输出
    if (p1 != nullptr)
        std::printf ("p1 no = %d\n", dynamic_cast<MyPoint *> (p1)->_no);
    else std::printf ("p1 does not exist\n");


    p2 = l.get (6);  // 用返回值输出
    if (p2 != nullptr)
        std::printf ("p2 no = %d\n", dynamic_cast<MyPoint *> (p2)->_no);
    else std::printf ("p2 does not exist\n");


    p3 = l.get (11);  // 取出一个不存在的
    if (p3 != nullptr)
        std::printf ("p3 no = %d\n", dynamic_cast<MyPoint *> (p3)->_no);
    else std::printf ("p3 does not exist\n");



    // 替换测试
    l.replace (0, MyPoint {1234, 1}); PRINT ("replace 0"); // 替换第一个
    l.replace (1, MyPoint {1234, 2}); PRINT ("replace 1"); // 替换第二个
    l.replace (5, MyPoint {1234, 3}); PRINT ("replace 5"); // 替换中间元素
    l.replace (8, MyPoint {1234, 4}); PRINT ("replace 8"); // 替换倒数第二个
    l.replace (9, MyPoint {1234, 5}); PRINT ("replace 9"); // 替换末尾元素


    // 测试删除
    l.remove (0); PRINT ("remove 0"); // 删除航点编号为0的航点
    l.remove (4); PRINT ("remove 4"); // 删除航点编号为4的航点
    l.remove (7); PRINT ("remove 7"); // 删除航点编号为7的航点
    l.remove (9); PRINT ("remove 9"); // 删除航点编号为9的航点 (不存在)


    // 插入测试
    l.insert (0, MyPoint {1234, 6}); PRINT ("insert 0"); // 插入并取代 编号0 航点 (最开始的位置)
    l.insert (1, MyPoint {1234, 7}); PRINT ("insert 1"); // 插入并取代 编号1 航点 (第二个位置)
    l.insert (5, MyPoint {1234, 8}); PRINT ("insert 5"); // 插入并取代 编号5 航点 (中间位置)
    l.insert (8, MyPoint {1234, 9}); PRINT ("insert 8"); // 插入并取代 编号8 航点 (倒数第二个位置)
    l.insert (11, MyPoint {1234, 10}); PRINT ("insert 11"); // 插入并取代 编号11 航点 (最后一个位置)
}

// 测试多线的增删改查等功能
void test_MultiLinear () {
    #define PRINT_MLC(mlc, line_id, str)                              \
        do {                                                          \
            auto & lc = mlc[line_id];                                 \
            std::printf ("%s (Line %d): ", str, line_id);             \
            for (int i = 0; i < lc.counts (); ++i) {                  \
                if (auto p = dynamic_cast<MyPoint *> (lc.get (i)))    \
                    if (p) std::printf ("%d(%d) ", p->_no, p->_info); \
            }                                                         \
            std::puts ("");                                           \
        } while (0)

    MultiLinear_Container_ct mlc;

    // 基础功能测试
    std::printf ("\n\n=== Basic Function Test ===\n");
    std::printf ("Initial counts: %d\n", mlc.counts ());
    std::printf ("Has line 100? %s\n", mlc.has (100) ? "true" : "false");

    // touch测试
    std::printf ("Touch line 100: %s\n", mlc.touch (100) ? "exists" : "created");
    std::printf ("Touch line 100 again: %s\n", mlc.touch (100) ? "exists" : "created");
    std::printf ("Current counts: %d\n", mlc.counts ());

    // 下标操作符测试 (200不存在, 自动创建)
    auto & lc1 = mlc[200];
    lc1.append (MyPoint {0, 10});
    PRINT_MLC (mlc, 200, "Auto-created line");

    // 多线操作测试
    std::printf ("\n=== Multi-line Operation Test ===\n");
    mlc[100].append (MyPoint {0, 1});
    mlc[100].append (MyPoint {1, 2});
    mlc[200].append (MyPoint {0, 3});
    PRINT_MLC (mlc, 100, "Line 100");
    PRINT_MLC (mlc, 200, "Line 200");

    // 跨线操作测试
    std::printf ("\n=== Cross-line Operation Test ===\n");
    mlc.insert (100, 1, MyPoint {123, 4});
    mlc.replace (200, 0, MyPoint {456, 5});
    PRINT_MLC (mlc, 100, "After insert");
    PRINT_MLC (mlc, 200, "After replace");

    // push/pop测试
    std::printf ("\n=== Push/Pop Test ===\n");
    Linear_Container_ct new_line {300};
    new_line.append (MyPoint {0, 6});
    std::printf ("Push new line 300: %s\n", mlc.push (std::move (new_line)) ? "success" : "failed");
    std::printf ("Push duplicate 300: %s\n", mlc.push (Linear_Container_ct {300}) ? "success" : "failed");
    mlc.pop (200);
    std::printf ("After pop line 200, counts: %d\n", mlc.counts ());

    // ID更新测试
    std::printf ("\n=== ID Update Test ===\n");
    std::printf ("Update 100->150: %s\n", mlc.updateLineID (100, 150) ? "success" : "failed");
    std::printf ("Check old 100: %s\n", mlc.has (100) ? "exists" : "missing");
    std::printf ("Check new 150: %s\n", mlc.has (150) ? "exists" : "missing");
    PRINT_MLC (mlc, 150, "Updated line");

    // 异常情况测试
    std::printf ("\n=== Edge Cases Test ===\n");
    std::printf ("Get non-existent line 999: %p\n", mlc.get (999, 0));
    std::printf ("Remove non-existent line: %s\n", mlc.remove (999, 0) ? "success" : "failed");
    std::printf ("Update non-existent line: %s\n", mlc.updateLineID (999, 0) ? "success" : "failed");
}

int main (const int argc, const char * const argv[], const char * const envp[]) {
    test_Linear ();
    test_MultiLinear ();
    return 0;
}
